using TerritoryGame.Domain.Common;
using TerritoryGame.Domain.ValueObjects;

namespace TerritoryGame.Domain.Entities;

public enum GameStatus
{
    Waiting,
    Playing,
    Finished
}

public class GameRoom : Entity<Guid>
{
    public string Name { get; private set; }
    public string RoomCode { get; private set; } // 房间代码
    public string? Password { get; private set; }
    public int MaxPlayers { get; private set; }
    public GameStatus Status { get; private set; }
    public int GameDuration { get; private set; } // 游戏时长（秒）
    public DateTime? StartTime { get; private set; }
    public DateTime CreatedAt { get; private set; }
    public DateTime UpdatedAt { get; private set; }
    public Guid? CreatedBy { get; private set; } // 房间创建者ID
    
    private readonly List<Player> _players = new();
    public IReadOnlyList<Player> Players => _players.AsReadOnly();
    
    private GameRoom() { }
    
    public GameRoom(Guid id, string name, int maxPlayers = 6, string? password = null, Guid? createdBy = null) : base(id)
    {
        Name = name ?? throw new ArgumentNullException(nameof(name));
        RoomCode = GenerateRoomCode();
        Password = password;
        MaxPlayers = maxPlayers;
        Status = GameStatus.Waiting;
        GameDuration = 180; // 3分钟
        CreatedBy = createdBy;
        CreatedAt = DateTime.UtcNow;
        UpdatedAt = DateTime.UtcNow;
    }

    public GameRoom(Guid id, string name, int maxPlayers, string? password, Guid? createdBy, int gameDurationSeconds) : base(id)
    {
        Name = name ?? throw new ArgumentNullException(nameof(name));
        RoomCode = GenerateRoomCode();
        Password = password;
        MaxPlayers = maxPlayers;
        Status = GameStatus.Waiting;
        GameDuration = gameDurationSeconds > 0 ? gameDurationSeconds : 180;
        CreatedBy = createdBy;
        CreatedAt = DateTime.UtcNow;
        UpdatedAt = DateTime.UtcNow;
    }
    
    public bool CanJoin(string? password = null, Guid? playerId = null)
    {
        if (Status != GameStatus.Waiting) return false;
        if (_players.Count >= MaxPlayers) return false;
        
        // 如果是房间创建者，不需要密码验证
        if (playerId.HasValue && CreatedBy.HasValue && playerId.Value == CreatedBy.Value)
        {
            return true;
        }
        
        // 否则需要密码验证
        if (!string.IsNullOrEmpty(Password) && Password != password) 
        {
            Console.WriteLine($"Password mismatch: Expected='{Password}', Provided='{password}'");
            return false;
        }
        return true;
    }
    
    public void AddPlayer(Player player)
    {
        if (!CanJoin(null, player.Id)) throw new InvalidOperationException("Cannot add player to room");
        if (_players.Any(p => p.Id == player.Id)) return;
        
        _players.Add(player);
        UpdatedAt = DateTime.UtcNow;
    }
    
    public void AddPlayer(Player player, bool skipPasswordValidation)
    {
        if (!skipPasswordValidation && !CanJoin(null, player.Id)) 
            throw new InvalidOperationException("Cannot add player to room");
        if (_players.Any(p => p.Id == player.Id)) return;
        
        _players.Add(player);
        UpdatedAt = DateTime.UtcNow;
    }
    
    public void RemovePlayer(Guid playerId)
    {
        var player = _players.FirstOrDefault(p => p.Id == playerId);
        if (player != null)
        {
            _players.Remove(player);
            UpdatedAt = DateTime.UtcNow;
        }
    }
    
    public void StartGame()
    {
        if (_players.Count < 2) throw new InvalidOperationException("Need at least 2 players to start");
        if (Status != GameStatus.Waiting) throw new InvalidOperationException("Game already started or finished");
        
        Status = GameStatus.Playing;
        StartTime = DateTime.UtcNow;
        UpdatedAt = DateTime.UtcNow;
    }
    
    public void EndGame()
    {
        Status = GameStatus.Finished;
        UpdatedAt = DateTime.UtcNow;
    }
    
    public void ResetGame()
    {
        Status = GameStatus.Waiting;
        StartTime = null;
        UpdatedAt = DateTime.UtcNow;
        
        // Reset player scores
        foreach (var player in _players)
        {
            player.ResetScore();
        }
    }
    
    public bool IsGameTimeUp()
    {
        if (StartTime == null || Status != GameStatus.Playing) return false;
        return DateTime.UtcNow >= StartTime.Value.AddSeconds(GameDuration);
    }
    
    public int GetRemainingTime()
    {
        if (StartTime == null || Status != GameStatus.Playing) return 0;
        var elapsed = (DateTime.UtcNow - StartTime.Value).TotalSeconds;
        return Math.Max(0, GameDuration - (int)elapsed);
    }
    
    private static string GenerateRoomCode()
    {
        const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        var random = new Random();
        return new string(Enumerable.Repeat(chars, 8).Select(s => s[random.Next(s.Length)]).ToArray());
    }
}
